#![allow(unused_imports)]
#![allow(unused_assignments)]
use axum::{
    extract::{Form, Json, Multipart},
    http:: HeaderMap,
    routing::post,
    Router
};
use tower_sessions::Session;
use crate::controller::user_controller::UserRequest;
use crate::controller::user_controller::pick_user_picture;
use crate::controller::user_controller::store_user_picture;
use crate::domain::UserBean;
use crate::serviceimpl::user_service::change_password_user as service_change_password_user;
use crate::serviceimpl::user_service::find_user_by_id as service_find_user_by_id;
use crate::serviceimpl::user_service::find_user_shadow_by_user_name as service_find_user_shadow_by_user_name;
use crate::serviceimpl::user_service::update_user as service_update_user;
use crate::utils::encrypt_util::verify_password;
use crate::utils::jwt_util::Claims;
use crate::utils::jwt_util::JWT_SECRET;
use jsonwebtoken::DecodingKey;
use jsonwebtoken::Validation;
use serde::Deserialize;
use serde_json::{Value,Map};
use tower_http::{trace::TraceLayer};


#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ChangeMyPasswordRequest {
	pub password: String,
	pub old_password:String,
}
pub fn profile_controller() -> Router {
	Router::new()
	.route("/findMyProfileUser", post(find_my_profile_user))
	.route("/updateMyProfileUser", post(update_my_profile_user))
	.route("/frontUpdateMyProfileUser", post(front_update_my_profile_user))
	.route("/changeMyPasswordUser", post(change_my_password_user))
	.route("/addUploadUserPhoto", post(add_upload_user_photo))
	.layer(TraceLayer::new_for_http())
}

pub async fn add_upload_user_photo(mut multipart:Multipart) ->String {
		while let Some(field) = multipart.next_field().await.unwrap() {
			let name = field.name().unwrap().to_string();
			if name == "files[]" {
				let content_type = field.content_type().unwrap().to_string();
				if content_type.starts_with("image/") {
					let data = field.bytes().await.unwrap();
					let data_str = base64::encode(data);
					store_user_picture("photo".to_string(),data_str.clone());

					let mut map = Map::new();
					map.insert("success".to_string(), Value::from(true));
					map.insert(
						"rows".to_string(),
						Value::from(data_str.clone()),
					);

					let resultjson = serde_json::to_string_pretty(&map).unwrap();
					return resultjson;
				}
			}
		}
		r#"{  "rows": null,  "success": true}"#.to_string()
}

pub async fn change_my_password_user(headers:HeaderMap,session:Session,Form(change_my_password_request):Form<ChangeMyPasswordRequest>) ->String {
	let password = change_my_password_request.password;
	let old_password = change_my_password_request.old_password;

	let stoken:std::option::Option<String> = session.get("token").await.unwrap();
	let mut token:String = "".to_string();
	match stoken {
		Some(stoken) => {
			token = stoken;
		},
		None => {
			token =  headers.get("X-Token").unwrap().to_str().unwrap().to_string();
		}
	}
	let claims:Claims = jsonwebtoken::decode(
		&token,
		&DecodingKey::from_secret(JWT_SECRET.as_bytes()),
		&Validation::default(),
	)
	.map(|data| data.claims).unwrap();
	let mut user = service_find_user_by_id(claims.sub).await.unwrap();
	let user_shadow = service_find_user_shadow_by_user_name(user.user_name.clone()).await.unwrap();
	let _success = verify_password(old_password.clone(), user_shadow.salt.clone(), user_shadow.password.clone()).await;
	match _success {
		Ok(_success) => {
			user.password = password.clone();
			let _result = service_change_password_user(user.clone()).await;
			match _result {
				Err(_) => {
					r#"{  "rows": null,  "success": false}"#.to_string()
				},
				Ok(_result) => {
					let mut map = Map::new();
					map.insert("success".to_string(), Value::from(true));
					map.insert(
						"rows".to_string(),
						Value::from(""),
					);

					let resultjson = serde_json::to_string_pretty(&map).unwrap();
					return resultjson;
				}
			}
		},
		Err(_) => {
			r#"{  "rows": null,  "success": false}"#.to_string()
		},
	}
}

pub async fn find_my_profile_user(headers:HeaderMap,session:Session) ->String {
	let stoken:std::option::Option<String> = session.get("token").await.unwrap();
	let mut token:String = "".to_string();
	match stoken {
		Some(stoken) => {
			token = stoken;
		},
		None => {
			token =  headers.get("X-Token").unwrap().to_str().unwrap().to_string();
		}
	}
	let claims:Claims = jsonwebtoken::decode(
		&token,
		&DecodingKey::from_secret(JWT_SECRET.as_bytes()),
		&Validation::default(),
	)
	.map(|data| data.claims).unwrap();
	let user = service_find_user_by_id(claims.sub).await;
		match user {
		Err(_) => {
			r#"{  "rows": null,  "success": true}"#.to_string()
		},
		Ok(user) => {
			let json = serde_json::to_string_pretty(&user).unwrap();

			let mut map = Map::new();
			map.insert("success".to_string(), Value::from(true));
			map.insert(
				"rows".to_string(),
				serde_json::from_str(&json).unwrap(),
			);

			let resultjson = serde_json::to_string_pretty(&map).unwrap();
			return resultjson;
		}
	}
}

pub async fn update_my_profile_user(headers:HeaderMap,session:Session,Json(user_request):Json<UserRequest>) ->String {
	let stoken:std::option::Option<String> = session.get("token").await.unwrap();
	let mut token:String = "".to_string();
	match stoken {
		Some(stoken) => {
			token = stoken;
		},
		None => {
			token =  headers.get("X-Token").unwrap().to_str().unwrap().to_string();
		}
	}
	let claims:Claims = jsonwebtoken::decode(
		&token,
		&DecodingKey::from_secret(JWT_SECRET.as_bytes()),
		&Validation::default(),
	)
	.map(|data| data.claims).unwrap();
	let old_user = service_find_user_by_id(claims.sub).await.unwrap();
	let user_name = user_request.user_name.unwrap_or_default();
	let active = user_request.active.unwrap_or_default();
	let first_name = user_request.first_name.unwrap_or_default();
	let last_name = user_request.last_name.unwrap_or_default();
	let email = user_request.email.unwrap_or_default();
	let isadmin = user_request.isadmin.unwrap_or_default();
	let gender = user_request.gender.unwrap_or_default();
	let address = user_request.address.unwrap_or_default();
	let phone = user_request.phone.unwrap_or_default();
	let description = user_request.description.unwrap_or_default();
	let ori_user = service_find_user_shadow_by_user_name(old_user.user_name.clone()).await.unwrap();
	let salt = ori_user.salt;
	let login_failure = ori_user.login_failure;
	let password = ori_user.password;
	let _current_user = service_find_user_by_id(old_user.id.clone()).await.unwrap();
	let current_photo = _current_user.photo;
	let mut my_photo = pick_user_picture("photo".to_string());
	if my_photo.len() == 0 && current_photo.len()>0 {
		my_photo = current_photo;
	}

	let user = UserBean{
	id : old_user.id,
	user_name : user_name,
	active : active,
	first_name : first_name,
	last_name : last_name,
	email : email,
	isadmin : isadmin,
	password : password,
	gender : gender,
	salt : salt,
	login_failure : login_failure,
	address : address,
	phone : phone,
	description : description,
	photo : my_photo,
	};

	let _result = service_update_user(user).await;
	match _result {
		Err(_) => {
			r#"{  "rows": null,  "success": true}"#.to_string()
		},
		Ok(_result) => {
			let mut map = Map::new();
			map.insert("success".to_string(), Value::from(true));
			map.insert(
				"rows".to_string(),
				Value::from(""),
			);

			let resultjson = serde_json::to_string_pretty(&map).unwrap();
			return resultjson;
		}
	}
}

pub async fn front_update_my_profile_user(headers:HeaderMap,session:Session,Json(user_request):Json<UserRequest>) ->String {
	let stoken:std::option::Option<String> = session.get("token").await.unwrap();
	let mut token:String = "".to_string();
	match stoken {
		Some(stoken) => {
			token = stoken;
		},
		None => {
			token =  headers.get("X-Token").unwrap().to_str().unwrap().to_string();
		}
	}
	let claims:Claims = jsonwebtoken::decode(
		&token,
		&DecodingKey::from_secret(JWT_SECRET.as_bytes()),
		&Validation::default(),
	)
	.map(|data| data.claims).unwrap();
	let old_user = service_find_user_by_id(claims.sub).await.unwrap();
	let mut ori_user = service_find_user_shadow_by_user_name(old_user.user_name.clone()).await.unwrap();
	let first_name = user_request.first_name.unwrap_or_default();
	let address = user_request.address.unwrap_or_default();
	let phone = user_request.phone.unwrap_or_default();

	ori_user.first_name = first_name;
	ori_user.address = address;
	ori_user.phone = phone;

	let _result = service_update_user(ori_user).await;
	match _result {
		Err(_) => {
			r#"{  "rows": null,  "success": false}"#.to_string()
		},
		Ok(_result) => {
			let mut map = Map::new();
			map.insert("success".to_string(), Value::from(true));
			map.insert(
				"rows".to_string(),
				Value::from(""),
			);

			let resultjson = serde_json::to_string_pretty(&map).unwrap();
			return resultjson;
		}
	}
}
